#include <string>
#include <iostream>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#include <BaseDedup.hpp>
#include <FastDedup.hpp>
#include <AccuDedup.hpp>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <assert.h>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
using namespace std;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
int main( int argc, char ** argv ) {

    if( argc != 7 ) {
        // the help message:
        cout << "usage:" << endl;
        cout << "zest -[i|e]  image_path  count_path  num_chunks  num_threads  -[f|a]" << endl;
        cout << endl;
        cout << "... -i or --impl: implicit sequence of file names such as image.0000, image.0001, image.0002, etc., up to image.[num_chunks-1]" << endl;
        cout << "... -e or --expl: explicit file names; num_chunks must be one"                  << endl;
        cout << "... image_path:   path to or filename of binary data for memory image"          << endl;
        cout << "... count_path:   path to or filename of binary data for page reference counts" << endl;
        cout << "... num_chunks:   number of files in the sequence; see -i option above"         << endl;
        cout << "... num_threads:  number of threads; must be less than or equal to num_chunks"  << endl;
        cout << "... -f or --fast: fast dedup, very small risk of being overly optimistic"       << endl;
        cout << "... -a or --accu: accurate dedup; takes 4x as long as fast"                     << endl;
        cout << endl;
        cout << "example usage with -i or --impl option:" << endl;
        cout << "zest -i /path/to/data/mem.image /path/to/data/ref.image 16 8 -a" << endl;
        cout << "... expects files /path/to/data/mem.image.0000 to /path/to/data/mem.image.0015 to exist" << endl;
        cout << "... expects files /path/to/data/ref.image.0000 to /path/to/data/ref.image.0015 to exist" << endl;
        cout << endl;
        cout << "example usage with -e or --expl option:" << endl;
        cout << "zest -e /path/to/data/mem.image /dev/null 1 1 -a" << endl;
        cout << "... uses only 1 file /path/to/data/mem.image" << endl;
        cout << "... reference counts are assumed to be zero (i.e. because perhaps you don't have this information)" << endl;
        cout << endl;
        exit( -1 );
    }
    
    // very simple cmd line argument parsing:
    const char * mem_image_path = argv[2];
    const char * ref_count_path = argv[3];
    const int32_t _numChunks  = atoi( argv[4] );
    const int32_t _numThreads = atoi( argv[5] );

    assert( _numChunks  > 0 );
    assert( _numThreads > 0 );
    const uint32_t numChunks  = _numChunks;
    const uint32_t numThreads = _numThreads;
    assert( numThreads <= numChunks );
    
    // implicit or explicit file names (and)
    // fast or accurate dedup
    const bool impl = ( string( argv[1] ) == "-i" ) || ( string( argv[1] ) == "--impl" );
    const bool nimp = ( string( argv[1] ) == "-e" ) || ( string( argv[1] ) == "--expl" );
    const bool accu = ( string( argv[6] ) == "-a" ) || ( string( argv[6] ) == "--accu" );
    const bool fast = ( string( argv[6] ) == "-f" ) || ( string( argv[6] ) == "--fast" );
    
    assert( nimp || impl );
    assert( accu || fast );
    if( nimp ) {
        // if file name is explicit, numChunks must be 1
        assert( numChunks == 1 );
    }
    
    // invoke the deduplicator:
    if( accu ) {
        
        AccuDedupMaster ddm( numChunks, numThreads, mem_image_path, ref_count_path, impl );
        ddm.RunDedup();
    }
    if( fast ) {
        
        FastDedupMaster ddm( numChunks, numThreads, mem_image_path, ref_count_path, impl );
        ddm.RunDedup();
    }
    
    return 0; 
}




